﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace Kindohm.Life.Library
{
    public class World
    {
       
        int lastCycleDuration = int.MinValue;
        Collection<HeartbeatObject> heartbeatObjects;
        Collection<HeartbeatObject> pendingDoneHeartbeatObjects;
        Collection<HeartbeatObject> pendingNewObjects;
        bool runningHeartbeats = false;
        int ticks;
        Simulation simulation;

        public World(Simulation simulation)
        {
            this.simulation = simulation;
            this.heartbeatObjects = new Collection<HeartbeatObject>();
            this.pendingDoneHeartbeatObjects = new Collection<HeartbeatObject>();
            this.pendingNewObjects = new Collection<HeartbeatObject>();
            ticks = 0;
        }

        public Simulation Simulation
        {
            get { return this.simulation; }
        }

        public int Ticks
        {
            get { return this.ticks; }
        }

        public Collection<HeartbeatObject> HeartbeatObjects
        {
            get { return this.heartbeatObjects; }
        }

        public void Tick()
        {
            int start = System.Environment.TickCount;

            this.RunHeartbeats();
            this.ProcessPendingDoneObjects();
            this.ProcessPendingNewObjects();

            int end = System.Environment.TickCount;
            this.lastCycleDuration = end - start;
            ticks++;
        }

        void RunHeartbeats()
        {
            this.runningHeartbeats = true;
            foreach (HeartbeatObject heartbeatObject in this.heartbeatObjects)
            {
                if (!heartbeatObject.Done)
                {
                    heartbeatObject.RunHeartbeat();
                }

                if (heartbeatObject.Done)
                {
                    this.pendingDoneHeartbeatObjects.Add(heartbeatObject);
                }
            }
            this.runningHeartbeats = false;
        }

        void ProcessPendingDoneObjects()
        {
            foreach (HeartbeatObject doneObject in this.pendingDoneHeartbeatObjects)
            {
                this.heartbeatObjects.Remove(doneObject);
            }
            this.pendingDoneHeartbeatObjects.Clear();
        }

        void ProcessPendingNewObjects()
        {
            foreach (HeartbeatObject newObject in this.pendingNewObjects)
            {
                this.heartbeatObjects.Add(newObject);
            }
            this.pendingNewObjects.Clear();
        }

        public void RegisterNewObject(HeartbeatObject newObject)
        {
            newObject.World = this;
            if (this.runningHeartbeats)
            {
                this.pendingNewObjects.Add(newObject);
            }
            else
            {
                this.heartbeatObjects.Add(newObject);
            }
        }

        public int LastCycleDuration
        {
            get { return this.lastCycleDuration; }
        }

        public WorldInfo GetWorldInfo()
        {
            int creatures = 0;
            int herbivores = 0;
            int carnivores = 0;
            int plants = 0;
            foreach (HeartbeatObject item in this.heartbeatObjects)
            {
                if (item is Creature)
                {
                    creatures++;
                }
                if (item is Herbivore)
                {
                    herbivores++;
                }
                if (item is Carnivore)
                {
                    carnivores++;
                }
                if (item is Plant)
                {
                    plants++;
                }
            }
            WorldInfo info = new WorldInfo(creatures, herbivores, carnivores, plants);
            return info;
        }

        public Collection<Creature> FindObjectsByName(string name)
        {
            Collection<Creature> items = new Collection<Creature>();
            foreach (HeartbeatObject item in this.heartbeatObjects)
            {
                if (item is Creature)
                {
                    if (item.Name.ToLower().StartsWith(name))
                    {
                        items.Add(item as Creature);
                    }
                }
            }
            return items;
        }
      
    }
}
